package accesoRepositorio;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;

/**
 * Esta clase contiene la funcionalidad necesaria para manejar una base de datos
 * 
 * @created 21-mar-2007 23:14:51
 * @version 2.0
 * @author Luis Miguel Merino Bonilla, Carmen Pastor Morales, Enrique Menor Santos
 */
public class ConexionBD {

	/**
	 * Atributo que almacena la conexion con la Base de datos
	 */
	private Connection con=null;

	private static String cadena_conexion=null;

	private static String user=null;

	private static String pass=null;

	private static String ip=null;
	
	/**
	 * Inicialización de atributos estáticos:
	 * Este bloque se ejecutará al cargarse las clases de la aplicación antes de ninguna
	 * otra cosa. Si no fuese correcto no arrancaría la aplicación.
	 */
	static{
		File f = new File("./IPGestorBD.txt");
		FileReader fr = null;
		try {
			fr = new FileReader(f);
		} catch (FileNotFoundException e) {
			System.err.println("Error en apertura de fichero de Conexion de BD. No se ha encontrado el fichero IPGestorBD.txt");
			System.exit (1);	
		}
		BufferedReader br = new BufferedReader(fr);
		try {
			ip = br.readLine();
			user = br.readLine();
			pass = br.readLine();
		} catch (IOException e) {
			System.err.println("Error en lectura de fichero de Conexion de BD: " + e.getMessage());
			System.exit (2);
		}
		if (ip==null ||ip.equals(""))
			{
			System.err.println("Error en lectura de la iIP desde el fichero IPGestorBD.txt");
			System.exit (3);
			}
		if (user==null ||user.equals(""))
			{
			System.err.println("Error en lectura del USUARIO desde el fichero IPGestorBD.txt");
			System.exit (3);
			}
		if (pass==null || pass.equals(""))
		{
			System.err.println("Error en lectura del PASSWORD desde el fichero IPGestorBD.txt");
			System.exit (3);
		}
		cadena_conexion = new String("jdbc:mysql://" + ip + "/Restaurante");
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
		}catch (Exception e) {
			System.err.println("No se encuentra el driver de mySql: " + e.getMessage());
			System.exit (4);
		}
	}
	
	/**
	 * Constructor de la clase. 
	 * 
	 */
	public ConexionBD() {
		
	}
	/**
	 * Abrir la conexion con la dase de datos. Si no existen las tablas de la
	 * Base de datos se crearán.
	 * 
	 * @return (boolean) Cierto si se ha podido establecer la conexion
	 * 
	 */
	public boolean abrir() {
		if (con != null) {
			System.err.println("Recuperando datos de la conexion...");
			return true;
		}
		System.out.print("Abriendo conexion con MySQL server...");
		try {
			con = DriverManager.getConnection(cadena_conexion, user, pass);
		} catch (SQLException e) {
			System.err.println("Error al crear conexion con BD: "+ e.getMessage());
			return false;
		}
		// Comprobamos si las tablas de la base de datos están creadas
		// Si no existen las creamos
		try {
			if (!existenTablas())
				{
				System.out.println("\nNo existen las tablas en la base de datos, van a ser creadas...");
				if(crearTablas())	
					System.out.println("Las tablas han sido creadas.");
				else
					{
					System.err.println("No se han podido crear las tablas.");
					return false;
					}
				}
		} catch (SQLException e) {
			System.err.println("Error al comprobar la existencia de las tablas de la BD: "+ e.getMessage());
			return false;
		}
		System.out.println("conexion abierta con exito");
		return true;
	}

	/**
	 * Método que comprueba si las tablas están creadas en la base de datos
	 * @return (boolean) Cierto si existen las tablas
	 * @throws SQLException Si se produce un error al crear un objeto
	 * 			statement para la conexion actual
	 */
	private boolean existenTablas() throws SQLException 
	{
		Statement s;
		s = con.createStatement();
		try{
			s.execute("SELECT * from Restaurante;");		
		}
		catch (SQLException e){
			{
			System.err.println("Se ha comprobado que no existen las tablas: "+e.getMessage());
			return false;	
			}
			
		}
		return true;		
	}
	/**
	 * Método que crea el esqueleto de las tablas de la base de 
	 * datos Restaurante en caso de que no existan 
	 * 
	 * @return (boolean) Cierto si se han creado las tablas correctamente
	 */
	private boolean crearTablas() 
		{
		Statement s;
		try {
			s = con.createStatement();
			}
		catch(SQLException e) 
			{
			System.err.println("Error al crear sentencia:"+e.getMessage());
			return false;
			}
		try {
			s.addBatch("CREATE TABLE Restaurante("+
				"id_restaurante	INT NOT NULL,"+
				"nombre_restaurante	TINYTEXT,"+
				"direccion		TINYTEXT,"+
				"telefono	INT,"+
				"CIF	VARCHAR(9),"+
				"PRIMARY KEY(id_restaurante)"+
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Mesa(" +
				"num_mesa	INT NOT NULL," +
				"estado		VARCHAR(10)," +
				"capacidad_actual 	INT," +
				"capacidad_maxima	INT," +
				"id_restaurante	INT," +
				"PRIMARY KEY(num_mesa)," +
				"FOREIGN KEY(id_restaurante)" +
				"REFERENCEs Restaurante(id_restaurante) " +
				"ON DELETE CASCADE ON UPDATE CASCADE" +
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Reserva(" +
				"nombre_cliente	VARCHAR(64) NOT NULL," +
				"fecha_hora		TIMESTAMP NOT NULL," +
				"num_comensales	INT," +
				"id_mesa_titular	INT," +
				"PRIMARY KEY(nombre_cliente, fecha_hora)," +
				"FOREIGN KEY(id_mesa_titular) REFERENCES Mesa(num_mesa) " +
				"ON DELETE CASCADE ON UPDATE CASCADE" +
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Carta(" +
				"id_carta	INT NOT NULL," +
				"nombre_carta	TINYTEXT," +
				"fecha_modificacion TIMESTAMP," +
				"id_restaurante INT," +
				"PRIMARY KEY(id_carta)," +
				"FOREIGN KEY(id_restaurante) REFERENCES Restaurante(id_restaurante) " +
				"ON DELETE CASCADE ON UPDATE CASCADE" +
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Seccion(" +
				"id_seccion	INT NOT NULL," +
				"nombre_seccion TINYTEXT," +
				"id_carta	INT," +
				"PRIMARY KEY(id_seccion)," +
				"FOREIGN KEY(id_carta) REFERENCES Carta(id_carta) " +
				"ON DELETE CASCADE ON UPDATE CASCADE" +
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Producto("+
				"id_producto INT NOT NULL,"+
				"nombre_producto VARCHAR(64) UNIQUE,"+
				"precio FLOAT,"+
				"disponible TINYTEXT,"+
				"id_seccion INT,"+
				"PRIMARY KEY(id_producto),"+
				"FOREIGN KEY(id_seccion) REFERENCES Seccion(id_seccion) " +
				"ON DELETE CASCADE ON UPDATE CASCADE"+
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE se_reservan("+
				"nombre_cliente	VARCHAR(64),"+
				"fecha_hora		TIMESTAMP,"+
				"id_mesa		INT,"+
				"PRIMARY KEY(nombre_cliente, fecha_hora, id_mesa),"+
				"FOREIGN KEY(nombre_cliente, fecha_hora) REFERENCES " +
				"Reserva(nombre_cliente, fecha_hora)"+ 
				"ON DELETE CASCADE ON UPDATE CASCADE"+
				") TYPE = INNODB;");
			s.addBatch("CREATE TABLE Pedido("+
				"id_pedido	 INT AUTO_INCREMENT,"+
				"num_comensales INT,"+
				"id_restaurante INT,"+
				"PRIMARY KEY (id_pedido),"+
				"FOREIGN KEY (id_restaurante)"+ 
				"REFERENCES Restaurante(id_restaurante)"+
				"ON DELETE CASCADE ON UPDATE CASCADE"+
				")TYPE=INNODB;");
			s.addBatch("CREATE TABLE Consumicion("+
				"id_consumicion 	INT AUTO_INCREMENT,"+
				"id_producto		INT,"+
				"id_pedido			INT,"+
				"estado			INT,"+
				"num_comensal		INT,"+
				"observaciones		TINYTEXT,"+
				"PRIMARY KEY (id_consumicion),"+
				"FOREIGN KEY (id_producto) REFERENCES Producto(id_producto)"+ 
				"ON DELETE CASCADE ON UPDATE CASCADE,"+
				"FOREIGN KEY (id_pedido) REFERENCES Pedido(id_pedido)"+ 
				"ON DELETE CASCADE ON UPDATE CASCADE"+
				")TYPE=INNODB;");
			s.addBatch("CREATE TABLE Observaciones("+
				"texto		VARCHAR(20)"+
				")TYPE=INNODB;");
			s.addBatch("CREATE TABLE esta_asociada("+
				"id_pedido INT,"+
				"num_mesa  INT,"+
				"PRIMARY KEY (id_pedido, num_mesa),"+
				"FOREIGN KEY (id_pedido) REFERENCES Pedido(id_pedido)"+ 
				"ON DELETE CASCADE ON UPDATE CASCADE,"+
				"FOREIGN KEY (num_mesa) REFERENCES Mesa(num_mesa)"+
				"ON DELETE CASCADE ON UPDATE CASCADE"+
				")TYPE=INNODB;");
			s.addBatch("insert into Restaurante VALUES(1, 'Donde sea', 'C/jeje',999533545,'C12313212');");
			s.addBatch("insert into Carta VALUES(1,'DondeSes',1);");
		} catch (SQLException e) {
			System.err.println("Error en sentencias de creacion de tablas: "+e.getMessage());
			return false;
		}
		try {
			s.executeBatch();
		} catch (SQLException e) {
			System.err.println("Error en ejecucion de creacion de tablas:"+e.getMessage());
			return false;
		}
		return true;
	}

	/**
	 * Ejecuta una consulta del tipo SELECT, que devuelve un objeto ResultSet
	 * 
	 * @param (String)
	 *            Comando de la consulta sql
	 */
	public ResultSet select(String comando) {
		Statement s;
		ResultSet rs = null;
		try {
			s = con.createStatement();
			rs=s.executeQuery(comando);
		} catch (/*SQL*/Exception e) {
			System.err.println("Error ejecutando select '"+comando+"': "+e);
			return null; 
		}
		return rs;
	}

	/**
	 * Cierra la conexion con la base de datos
	 */
	public void cerrar() {// LO TENIAN COMENTADO, XQ????
		System.out.print("Cerrando conexion con MySQL server...");
		try {
			if (con != null)
				con.close();
		} catch (SQLException e) {
			System.err.println("Error al cerrar la DB: " + e);
		}
		System.out.println("conexion cerrada con exito");
	}

	/**
	 * Ejecuta consultas SQL del tipo INSER, UPDATE o DELETE que no devuelven un
	 * resultado de consulta
	 * 
	 * @param (String) Comando de la consulta sql
	 * @return (boolean) Cierto si se ha ejecutado la consulta con exito (caso en el que
	 * la sentencia devuelve un entero correspondiente al num de filas modificadas)
	 */
	public boolean update(String comando) {
		Statement s;
		try {
			s = con.createStatement();
			s.executeUpdate(comando);
		} catch (SQLException e) { 
			System.err.println("Error ejecutando sentencia update '"+comando+"': "+e);
			return false;
		}
		return true;
	}

	/**
	 * Ejecuta consultas SQL del tipo DELETE que no devuelven un resultado de
	 * consulta
	 * 
	 * @param (String) Comando de la consulta sql
	 * @return (boolean) Cierto si se ha ejecutado la consulta con exito
	 */
	public boolean delete(String comando) {
		return this.update(comando);
	}

	/**
	 * Ejecuta consultas SQL del tipo INSERT que no devuelven un resultado de
	 * consulta
	 * 
	 * @param (String) Comando de la consulta sql
	 * @return (boolean) Cierto si se ha ejecutado la consulta con exito
	 */
	public boolean insert(String comando) {
		return this.update(comando);
	}

	public int generaId(String tabla, String columna) {
		int id = 100;

		try {
			ResultSet rs = (ResultSet) this.select("SELECT MAX(" + columna
					+ ")+1 FROM " + tabla);
						
			if(rs.next())
				id=rs.getInt(1);
			
		} catch (Exception e) {
			System.out.println("Exc:" + e);
		}

		return id;
	}

}
